#include "RenderController.h"
#include "Hud.h"
#include "../Animation/AnimationManager.h"

#include "ShaderManager.h"

//Static objects
unsigned int RenderController::lastLoadedIndex;
unsigned int RenderController::lastLoadedMatrix[NUM_OBJECTS];
RenderController::StaticObjects RenderController::staticObjects;

//Debug geometry
unsigned int RenderController::debugLastLoadedIndex;
unsigned int RenderController::debugLastLoadedMatrix[NUM_DEBUG_OBJECTS];
RenderController::DebugGeometry RenderController::debugGeometry;

//Players
RenderGObject	RenderController::players[NUM_PLAYERS];
XMMATRIX		RenderController::playerWorld[NUM_PLAYERS];
unsigned int	RenderController::lastLoadedPlayer;

//timer
Timer			RenderController::timer;

//They see me threadin
CRITICAL_SECTION RenderController::criticalSection;

XMMATRIX RenderController::viewProjection;

RenderController::RenderController()
{
}

RenderController::~RenderController()
{
}

void RenderController::Initialize()
{
	debugLastLoadedIndex = 0;
	lastLoadedIndex = 0;
	lastLoadedPlayer = 0;
	ZeroMemory(lastLoadedMatrix,sizeof(unsigned int)*NUM_OBJECTS);
	ZeroMemory(debugLastLoadedMatrix,sizeof(unsigned int)*NUM_DEBUG_OBJECTS);
	InitializeCriticalSection(&criticalSection);
	Hud::Initialize();
	timer.Init();
}

unsigned int RenderController::LoadObject(const char* const _filePath)
{
	staticObjects.objects[lastLoadedIndex].LoadObject(_filePath);

	return lastLoadedIndex++;
}

unsigned int RenderController::LoadPlayer(const char* const _filePath)
{
	players[lastLoadedPlayer].LoadObject(_filePath);

	return lastLoadedPlayer++;
}

void RenderController::SetPlayerPosition(unsigned int _index, float _posX, float _posY, float _posZ)
{ 
	playerWorld[_index] = XMMatrixTranslation(_posX, _posY, _posZ);
}

void RenderController::SetStaticObjectPosition(unsigned int _index, float _posX, float _posY, float _posZ)
{
	staticObjects.world[_index][lastLoadedMatrix[_index]++] = XMMatrixTranslation(_posX, _posY, _posZ);
}

void RenderController::Render()
{
	for(unsigned int objectIndex = 0; objectIndex < lastLoadedIndex; ++objectIndex)
	{
		ShaderManager::SetMaterialDiffuse(staticObjects.objects[objectIndex].GetMaterial());

		for(unsigned int matrixIndex = 0; matrixIndex < lastLoadedMatrix[objectIndex]; ++matrixIndex)
		{
			ShaderManager::SetMVP(XMMatrixMultiply(staticObjects.world[objectIndex][matrixIndex],viewProjection));
			staticObjects.objects[objectIndex].RenderObject();
		}
	}
	static double time = 0.0;
	timer.TimeStep();
	time += timer.GetDeltaTime();
	if(time > 16.0)
	{
		AnimationManager::PlayAnimations();
		time = 0.0;
	}

	for(unsigned int playerIndex = 0; playerIndex < lastLoadedPlayer; ++playerIndex)
	{
		ShaderManager::SetMaterialDiffuse(players[playerIndex].GetMaterial());
		ShaderManager::SetMVP(XMMatrixMultiply(playerWorld[playerIndex],viewProjection));
		players[playerIndex].RenderObject();
	}

	RenderHUD();
}

void RenderController::RenderHUD()
{
	Hud::Render();
}

void RenderController::SetViewProjection(XMFLOAT4X4 _vp)
{
	EnterCriticalSection(&criticalSection);
	viewProjection = XMLoadFloat4x4(&_vp);
	LeaveCriticalSection(&criticalSection);
}

unsigned int RenderController::LoadDebugGeometry(DEBUG_SHAPE _shape, float _xScale, float _yScale, float _zScale)
{
	switch(_shape)
	{
	case BOX:
		debugGeometry.objects[lastLoadedIndex].CreateBox(_xScale, _yScale, _zScale);// call create box
		break;
	case PLANE:
		debugGeometry.objects[lastLoadedIndex];// call create plane
		break;
	}

	return debugLastLoadedIndex++;
}

void RenderController::SetDebugGeometryPosition(unsigned int _index, float _posX, float _posY, float _posZ)
{
	debugGeometry.world[_index][debugLastLoadedMatrix[_index]++] = XMMatrixTranslation(_posX, _posY, _posZ);
}

void RenderController::RenderDebugGeometry()
{
	for(unsigned int objectIndex = 0; objectIndex < debugLastLoadedIndex; ++objectIndex)
	{
		for(unsigned int matrixIndex = 0; matrixIndex < debugLastLoadedMatrix[objectIndex]; ++matrixIndex)
		{
			ShaderManager::SetMVP(XMMatrixMultiply(debugGeometry.world[objectIndex][matrixIndex],viewProjection));
			debugGeometry.objects[objectIndex].RenderObject();
		}
	}
}